﻿using Abp.Application.Services.Dto;
using Abp.Authorization.Users;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.UI;
using AbpProject.Menus.Dto;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbpProject.Menus
{
    public class MenuAppService : AbpProjectAppServiceBase, IMenuAppService
    {
        private readonly IRepository<AbpMenu, long> _menuRepository;
        private readonly IRepository<AbpRoleMenu, long> _roleMenuRepository;
        private readonly IRepository<UserRole, long> _userRoleRepository;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        
        public MenuAppService(
            IRepository<AbpMenu, long> menuRepository,
            IRepository<AbpRoleMenu, long> roleMenuRepository,
            IRepository<UserRole, long> userRoleRepository,
            IUnitOfWorkManager unitOfWorkManager
            )
        {
            _menuRepository = menuRepository;
            _roleMenuRepository = roleMenuRepository;
            _userRoleRepository = userRoleRepository;
            _unitOfWorkManager = unitOfWorkManager;
            
        }

        /// <summary>
        /// 获取用户菜单
        /// </summary>
        /// <returns></returns>
        public async Task<ListResultDto<AbpMenuModel>> GetUserMenuList()
        {
            //获取登录者的角色
            var roleList = _userRoleRepository.GetAll().AsNoTracking().Where(r => r.UserId.Equals(AbpSession.UserId));

            var role = new List<long>();
            foreach (var item in roleList)
            {
                role.Add(item.RoleId);
            }
            //获取角色菜单 去重
            var roleMenuList = (from roleMenu in _roleMenuRepository.GetAll().AsNoTracking()
                                where role.Contains(roleMenu.RoleId)
                                //group roleMenu by roleMenu.MenuId into tab
                                select new
                                {
                                    roleMenu.MenuId
                                }).Distinct().ToList();

            var menuList = (from menu in _menuRepository.GetAll().AsNoTracking()
                            join roleMenu in roleMenuList on menu.Id equals roleMenu.MenuId
                            where menu.Type.Equals("menu")
                            select menu.MapTo<AbpMenuDto>()).ToList();
            var re = GetTreeParent(menuList);
            return new ListResultDto<AbpMenuModel>(re);
        }

        /// <summary>
        /// 获取用户按钮
        /// </summary>
        /// <returns></returns>
        public async Task<ListResultDto<AbpMenuDto>> GetUserMenuButtonList()
        {
            //获取登录者的角色
            var roleList = _userRoleRepository.GetAll().AsNoTracking().Where(r => r.UserId.Equals(AbpSession.UserId));

            var role = new List<long>();
            foreach (var item in roleList)
            {
                role.Add(item.RoleId);
            }
            //获取角色菜单 去重
            var roleMenuList = (from roleMenu in _roleMenuRepository.GetAll().AsNoTracking()
                                where role.Contains(roleMenu.RoleId)
                                //group roleMenu by roleMenu.MenuId into tab
                                select new
                                {
                                    roleMenu.MenuId
                                }).Distinct().ToList();

            var menuList = (from menu in _menuRepository.GetAll().AsNoTracking()
                            join roleMenu in roleMenuList on menu.Id equals roleMenu.MenuId
                            where menu.Type.Equals("button")
                            select menu.MapTo<AbpMenuDto>()).ToList();
            //var re = GetTreeParent(menuList);
            return new ListResultDto<AbpMenuDto>(menuList);
        }


        /// <summary>
        /// 获取全部菜单
        /// </summary>
        /// <returns></returns>
        public async Task<ListResultDto<AbpMenuModel>> GetMenuListAll()
        {
            var tenantId = AbpSession.TenantId;
            var menuList = (from menu in _menuRepository.GetAll().AsNoTracking()
                            where menu.Type.Equals("menu")  && menu.TenantId== tenantId
                            select menu.MapTo<AbpMenuDto>()).ToList();
            var re = GetTreeParent(menuList);
            return new ListResultDto<AbpMenuModel>(re);
        }

        /// <summary>
        /// 获取全部菜单包括元素
        /// </summary>
        /// <returns></returns>
        public async Task<ListResultDto<AbpMenuModel>> GetMenuAll()
        {
            var tenantId = AbpSession.TenantId;
            var menuList = (from menu in _menuRepository.GetAll().AsNoTracking()
                            where  menu.TenantId== tenantId
                            select menu.MapTo<AbpMenuDto>()).ToList();
            var re = GetTreeParent(menuList);
            return new ListResultDto<AbpMenuModel>(re);
        }


        /// <summary>
        /// 获取菜单按钮
        /// </summary>
        /// <returns></returns>
        public async Task<ListResultDto<AbpMenuDto>> GetButtonByMenuId(EntityDto<long> input)
        {
            var menuList = (from menu in _menuRepository.GetAll().AsNoTracking()
                            where menu.ParentId == input.Id && menu.Type.Equals("button")
                            select menu.MapTo<AbpMenuDto>()).ToList();
            // var re = GetTreeParent(menuList);
            return new ListResultDto<AbpMenuDto>(menuList);
        }



        /// <summary>
        /// 根据角色ID  获取菜单包含元素   标识是否拥有
        /// </summary>
        /// <param name="inout"></param>
        /// <returns></returns>
        public async Task<GetMenuListByRoleIdOutput> GetMenuListAllByRoleId(EntityDto<long> input)
        {
            var menuList = (from menu in _menuRepository.GetAll().AsNoTracking()
                            select menu.MapTo<AbpMenuDto>()).ToList();
            var re = GetTreeParent(menuList);
            var role = _roleMenuRepository.GetAll().AsNoTracking().Where(r => r.RoleId == input.Id);

            var list = new List<long>();
            foreach (var item in role)
            {
                list.Add(item.MenuId);
            }
            return new GetMenuListByRoleIdOutput
            {
                RoleMenuList = list.ToArray(),
                MenuButtonModel = re
            };
        }


        public async Task CreateOrUpdateMenu(CreateOrUpdateMenuInput input)
        {
            var tenantId = AbpSession.TenantId;
            var parentMenu = await _menuRepository.FirstOrDefaultAsync(r => r.Id == input.ParentId);
            if (input.Id.Value > 0)
            {
                var menu = await _menuRepository.FirstOrDefaultAsync(r => r.Id == input.Id.Value);
                menu.Icon = input.Icon;
                menu.Title = input.Title;
                menu.Path = input.Path;
                menu.ParentId = input.ParentId;
                menu.TenantId = tenantId;
                await _menuRepository.InsertOrUpdateAsync(menu);

            }
            else
            {
                var menu = new AbpMenu();
                menu.Icon = input.Icon;
                menu.Title = input.Title;
                menu.Path = input.Path;
                menu.ParentId = input.ParentId;
                menu.Type = "menu";
                menu.TenantId = tenantId;
                await _menuRepository.InsertOrUpdateAsync(menu);
            }

        }


        /// <summary>
        /// 新增修改按钮
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task CreateOrUpdateButton(CreateOrUpdateButtonInput input)
        {
            var tenantId = AbpSession.TenantId;
            var menu = await _menuRepository.FirstOrDefaultAsync(r => r.Id == input.MenuId);
            var button = new AbpMenu();
            if (input.Id.HasValue)
            {
                var checkButton = await _menuRepository.FirstOrDefaultAsync(r => r.ParentId == input.MenuId && r.Id != input.Id && r.Code.Equals(input.ButtonCode) && r.Type.Equals("button"));
                if (checkButton != null)
                {
                   throw  new UserFriendlyException("代码已存在!");
                }
                else
                {
                    button = await _menuRepository.FirstOrDefaultAsync(r => r.Id == input.Id);
                    button.Title = input.ButtonName;
                    button.Code = input.ButtonCode;
                    button.Name = input.ButtonName;
                    button.TenantId = tenantId;
                }

            }
            else
            {
                var checkButton = await _menuRepository.FirstOrDefaultAsync(r => r.ParentId == input.MenuId && r.Code.Equals(input.ButtonCode) && r.Type.Equals("button"));
                if (checkButton != null)
                {
                    throw new UserFriendlyException("代码已存在!");
                }
                else
                {
                    button.ParentId = menu.Id;
                    button.Path = menu.Path;
                    button.Title = input.ButtonName;
                    button.Code = input.ButtonCode;
                    button.Name = input.ButtonName;
                    button.Type = "button";
                    button.TenantId = tenantId;

                }
            }
            await _menuRepository.InsertOrUpdateAsync(button);
        }

        /// <summary>
        /// 删除菜单或者按钮
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task Delete(EntityDto<long> input)
        {
            await _menuRepository.DeleteAsync(r => r.Id == input.Id);
        }


        public async Task InsertRoleMunuAndButton(RoleMunuAndButtonInput input)
        {
            var tenantId = AbpSession.TenantId;
            _roleMenuRepository.Delete(r => r.RoleId == input.RoleId);
            foreach (var item in input.Menus)
            {
                var menu = new AbpRoleMenu
                {
                    RoleId = input.RoleId,
                    MenuId = item.Id,
                    TenantId= tenantId
                };
                _roleMenuRepository.Insert(menu);
            }

        }

        /// <summary>
        /// 转化成树结构
        /// </summary>
        /// <param name="menuList">菜单的平级list</param>
        /// <returns></returns>
        private List<AbpMenuModel> GetTreeParent(List<AbpMenuDto> menuList)
        {
            var dic = new Dictionary<long, AbpMenuModel>(menuList.Count);
            foreach (var chapter in menuList)
            {
                dic.Add(chapter.Id, new AbpMenuModel { Id = chapter.Id, Title = chapter.Title, Path = chapter.Path, ParentId = chapter.ParentId, Icon = chapter.Icon });
            }
            foreach (var chapter in dic.Values)
            {
                if (dic.ContainsKey(chapter.ParentId.Value))
                {
                    if (dic[chapter.ParentId.Value].Children == null)
                    {
                        dic[chapter.ParentId.Value].Children = new List<AbpMenuModel>();

                    }
                    dic[chapter.ParentId.Value].Children.Add(chapter);
                }
            }
            return dic.Values.Where(t => t.ParentId == 0).ToList();
        }

        /// <summary>
        /// 校验是否已经生成菜单
        /// </summary>
        /// <returns></returns>
        public async Task<bool> IsHasMenuByTenant()
        {
            var tenantId = AbpSession.TenantId;
            var result = await _menuRepository.FirstOrDefaultAsync(r => r.TenantId == tenantId);
            if (result == null)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
    }
}
